#include <stdlib.h>
#include <math.h>

#include "../SparceMatrix/sparse_matrix.h"


#include "Vector.h"
#include "../../libs/Utils/Utils.h"
#include "../Utils/BasicTypes.h"

elem* MultVectorByMatrix(const elem* matrix, const elem* vector, unsigned size)
{
	elem* ret = NULL;
	int i = 0, j = 0, matrixIter = 0;
	
	NAssert(MemoryAssert(2, matrix, vector));
	NAssert(MemoryAssert(1, ret = (elem*)malloc(sizeof(elem) * size)));
	
	for (i = 0; i < size; i++)
	{
		ret[i] = 0;
		for (j = 0; j < size; j++)
			ret[i] += vector[j] * matrix[matrixIter++]; 
	}
	
	return ret;
}

elem SumOfVector(const elem* vector, unsigned size)
{
	elem ret = 0;
	unsigned l;
	
	for (l = 0; l < size; l++)
		ret += vector[l];
	
	return ret;
}

elem* MultVectorByScalar (const elem* vector, elem scalar, elem* ret, unsigned size)
{
	int i = 0;
	
	NAssert(vector != NULL);
	
	for (i = 0; i < size; i++)
		ret[i] = vector[i] * scalar;
	
	return ret;
}

elem* CreateMultVectorByScalar (const elem* vector, elem scalar, unsigned size)
{
	elem* ret = NULL;
	
	NAssert(vector != NULL);
	NAssert(MemoryAssert(1, ret = (elem*)malloc(sizeof(elem) * size)));
	
	return MultVectorByScalar(vector, scalar, ret, size);
}


elem* MultedVector (const elem* vector1, const elem* vector2, elem* ret, unsigned size)
{
	int i = 0;
	
	NAssert(vector1 != NULL && vector2 != NULL && ret != NULL);
	
	for (i = 0; i < size; i++)
		ret[i] = vector1[i] * vector2[i];
	
	return ret;
}

elem* CreateMultedVector (const elem* vector1, const elem* vector2, unsigned size)
{
	elem* ret = NULL;

	NAssert(vector1 != NULL && vector2 != NULL && ret != NULL);
	NAssert(MemoryAssert(1, ret = (elem*)malloc(sizeof(elem) * size)));
	
	return MultedVector(vector1, vector2, ret, size);
}

elem ScalarProduct (const elem* vector1, const elem* vector2, unsigned size)
{
	elem ret = 0;
	int i = 0;
	
	for (i = 0; i < size; i++)
		ret += vector1[i] * vector2[i];
	
	return ret;
}

/*
 * In: vector of elements, numlist.
 * Error: if vector is null or numlist is null or memeory allocation failed then null.
 * Out: new vector whos element's indexes are in the numlist.
 */

elem* PartialVector (const elem * vector, const NumList* numList)
{
	elem* ret = NULL;
	int counter = 0;
	
	NAssert(MemoryAssert(1, numList));
	NAssert(MemoryAssert(1, ret = (elem*)malloc(sizeof(elem) * numList->size)));
	
	for (; numList->next != NULL; numList = numList->next)
		ret[counter++] = vector[numList->value];
	
	return ret;
}


elem* SumVectors (const elem* vector1, const elem* vector2, elem* ret, unsigned size, bool isSum)
{
	int i = 0;
	
	NAssert(vector1 != NULL && vector2 != NULL && ret != NULL);
	
	if (isSum)
		for (i = 0; i < size; i++)
			ret[i] = vector1[i] + vector2[i];
	else
		for (i = 0; i < size; i++)
			ret[i] = vector1[i] - vector2[i];
	
	
	return ret;
}

elem NormVector (const elem* vector, unsigned size)
{
	return sqrt(ScalarProduct(vector, vector, size));
}

bool BrutalRoundVector (elem* vector, unsigned size)
{
	int l = 0;
	FAssert(vector != NULL);
	
	for (l = 0; l < size; l++)
		vector[l] = (vector[l] > 0.00001) ? 1 : -1;
		
	return TRUE;
}

void InitVectorWithBool (bool* vector, bool init, unsigned size)
{
	int i = 0;
	for (i = 0; i < size; i++)
		vector[i] = init;
}

void InitVectorWithElem (elem* vector, elem init, unsigned size)
{
	int i = 0;
	for (i = 0; i < size; i++)
		vector[i] = init;
}

/**
 * @pre (size > 0)
 * 
 */
unsigned FindMaxIndex(const elem* vector, unsigned size)
{
	unsigned i, maxIndex = 0;
	elem maxValue = vector[0];
	
	for (i = 0; i < size; i++)
		if (maxValue < vector[i])
		{
			maxIndex = i;
			maxValue = vector[i];
		}
	
	return maxIndex;
}

unsigned FindMaxIndexUnmoved(const elem* vector, const bool* moved, unsigned size)
{
	unsigned i = 0, maxIndex = 0;
	elem maxValue = vector[0];

	while (moved[maxIndex++]);
	maxValue = vector[--maxIndex];
	
	for (i = maxIndex + 1; i < size; i++)
		if ((!moved[i]) && (maxValue < vector[i]))
		{
			maxIndex = i;
			maxValue = vector[i];
		}
	
	return maxIndex;
}
